package com.sping.gobang.game;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sping.gobang.DemoApplication;
import com.sping.gobang.common.constant.Constants;
import com.sping.gobang.mapper.UserMapper;
import com.sping.gobang.pojo.datapbject.User;
import com.sping.gobang.pojo.request.GameRequest;
import com.sping.gobang.pojo.response.GameResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

@Data
@Slf4j
public class Room {
    private String roomId;
    private User user1;
    private User user2;
    //先手方玩家的id
    private int whiteUser;
    public Room(){
        //使用uuid来作为房间id
        roomId= UUID.randomUUID().toString();
        //通过Spring上下文来获取前面的RoomManager和OnlineUserManager和UserMapper
        onlineUserManager= DemoApplication.run.getBean(OnlineUserManager.class);
        roomManager=DemoApplication.run.getBean(RoomManager.class);
        userMapper=DemoApplication.run.getBean(UserMapper.class);

    }


    private ObjectMapper objectMapper=new ObjectMapper();

    private RoomManager roomManager;

    private OnlineUserManager onlineUserManager;

    private UserMapper userMapper;
    //二维数组用来表示棋盘
    //0表示当前位置未落子，初始化好的int 二维数组 ，就相当于全是0
    //1表示user1的落子位置
    //2表示user2的落子位置
    private int[][] board=new int[Constants.MAX_ROW][Constants.MAX_COL];
    public void putChess(String reqJson) throws IOException {
        //1.记录当前落子的位置
        //获取客户端给服务器发送的数据，从消息的载荷里面获取数据
        //当前这个数据载荷是一个JSON格式的字符串，需要把它转化成java对象
        GameRequest gameRequest = objectMapper.readValue(reqJson, GameRequest.class);
        GameResponse gameResponse=new GameResponse();
        //当前这个子是玩家1落得还是玩家2落得，根据这个玩家1和玩家2来决定往数组中是写1还是写2
        int chess=gameRequest.getUserId()==user1.getUserId()?1:2;
        int row=gameRequest.getRow();
        int col=gameRequest.getCol();
        if(board[row][col]!=0){
            //客户端已经针对重复落子进行判定，此处为了程序的健壮性，再进行判断
            log.info("当前位置 ("+row+","+col+") 已经有子啦!");
            return;
        }
        board[row][col]=chess;
        //2.打印当前棋盘的信息，方便来观察局势，也方便验证胜负关系的判断
        printBoard();
        //3.进行胜负判定
        int winner=CheckWinner(row,col,chess);
        //4.给房间中的所有客户端都返回响应
        gameResponse.setMessage("putChess");
        gameResponse.setUserId(gameRequest.getUserId());
        gameResponse.setRow(row);
        gameResponse.setCol(col);
        gameResponse.setWinner(winner);

        //想要给用户发送websocket数据，就需要获取到 这个用户的WebSocketSession
        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromGameRoom(user2.getUserId());
        if(session1==null){
            gameResponse.setWinner(user2.getUserId());
            log.info("玩家1掉线,则玩家2直接获胜");
        }
        if(session2==null){
            gameResponse.setWinner(user1.getUserId());
            log.info("玩家2掉线,则玩家1直接获胜");
        }
        //把想要构造程JSON字符串，通过session进行传输
        String respJson = objectMapper.writeValueAsString(gameResponse);
        if(session1!=null){
            session1.sendMessage(new TextMessage(respJson));
        }
        if(session2!=null){
            session2.sendMessage(new TextMessage(respJson));
        }
        //5.若当前胜负已分，销毁房间
        if(gameResponse.getWinner()!=0){
            //胜负已分
            log.info("游戏结束!房间即将销毁! roomId="+roomId+"获胜方为:"+gameResponse.getWinner());
            //处理平局情况
            if(gameResponse.getWinner()==-1){
                log.info("游戏平局");
                //则只用增加totalCount，score和winCount不变
                userMapper.isDraw(user1.getUserId());
                userMapper.isDraw(user2.getUserId());
                //销毁房间
                roomManager.remove(roomId,user1.getUserId(),user2.getUserId());
            }else{
                //更新获胜方和失败方的信息
                int winUserId=gameResponse.getWinner();
                int loseUserId=gameResponse.getWinner()==user1.getUserId()?user2.getUserId():user1.getUserId();
                userMapper.userWin(winUserId);
                userMapper.userLose(loseUserId);
                //销毁房间
                roomManager.remove(roomId,user1.getUserId(),user2.getUserId());
            }
        }



    }

    private void printBoard() {
        //打印棋盘
        log.info("[打印棋盘信息]"+roomId);
        System.out.println("======================================");
        for(int r=0;r<Constants.MAX_ROW;r++){
            for(int c=0;c<Constants.MAX_COL;c++){
                System.out.print(board[r][c]+" ");
            }
            System.out.println();
        }
        System.out.println("======================================");
    }

    private int CheckWinner(int row, int col, int chess) {
        //检查行
        //五个子连着而且这五个字的和玩家落下的子是一样的，要么全1，要么全0
        for(int c=col-4;c<=col;c++){
           try{
               if(board[row][c]==chess&&board[row][c+1]==chess
                       &&board[row][c+2]==chess&&board[row][c+3]==chess
                       &&board[row][c+3]==chess){
                   return chess==1?user1.getUserId():user2.getUserId();
               }

           }catch (ArrayIndexOutOfBoundsException e){
               continue;
           }
        }
        //检查列
        for(int r=row-4;r<=row;r++){
            try{
                if(board[r][col]==chess&&board[r+1][col]==chess
                        &&board[r+2][col]==chess&&board[r+3][col]==chess
                        &&board[r+4][col]==chess){
                    return chess==1?user1.getUserId():user2.getUserId();
                }


            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }
        //检查左对角线
        for(int r=row-4,c=col-4;r<=row&&c<=col;r++,c++){
            try{
                if(board[r][c]==chess&&board[r+1][c+1]==chess
                        &&board[r+2][c+2]==chess&&board[r+3][c+3]==chess
                        &&board[r+4][c+4]==chess){
                    return chess==1?user1.getUserId():user2.getUserId();
                }


            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }
        //检查右对角线
        for(int r=row-4,c=col-4;r<=row&&c>=col;r++,c--){
            try{
                if(board[r][c]==chess&&board[r+1][c-1]==chess
                        &&board[r+2][c-2]==chess&&board[r+3][c-3]==chess
                        &&board[r+4][c-4]==chess){
                    return chess==1?user1.getUserId():user2.getUserId();
                }


            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }

        //TODO 如果棋盘用完了,且没有分出胜负，算平局
        //检查是否平局
        boolean isDraw=true;//假设平均(平局时，棋盘已经满了)
        for(int r=0;r<Constants.MAX_ROW;r++){
            for(int c=0;c<Constants.MAX_COL;c++){
                if(board[r][c]==0){//如果发现任何一个位置是空位置，就不是平局
                    isDraw=false;//不是平局
                    break;//跳出内层循环
                }
            }
            if(!isDraw){
                break;//如果已经确定不是平局，直接跳出外层循环
            }
        }
        if(isDraw){
            return -1;//使用-1表示平局
        }


        //胜负未分
        return 0;

    }
}
